/*
 * Created by Huang 嵘才 on 18-5-7 下午6:04
 * Copyright (c) 2018. All rights reserved.
 * Last modified 18-5-7 下午6:04
 */

package io.esirong.widget.view;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import androidx.fragment.app.Fragment;

import java.lang.ref.WeakReference;

/**
 * 时钟振荡器(频率精100毫秒)
 * 设定振荡的频率
 * 设定振荡开始的时间点
 * 设定振荡结束的时间点
 * 注册振荡回调
 * 如果振荡器的结束时间是<0.振器会持续不断
 * 振荡器默认开始时间是当现系统时间
 * 默认是:当前开始，持续不断
 * 模式：当前->无限，;开始点->无限; 开始点->结束点
 * Created by 黄嵘才(HuangRc) on 2018/5/7.
 */

public final class ClockOscillator {
    /**
     * 振荡事件
     */
    private static final int TICK_WHAT = 2;
    /**
     * 振荡开始的时间点
     */
    private Long start;
    /**
     * 振荡结束的时间点
     */
    private Long end;
    /**
     * 振荡的频率
     */
    private Long interval = 1000L;
    /**
     * 振荡的开始
     */
    private boolean mStarted;
    /**
     * 振荡的进行
     */
    private boolean mRunning;


    private long lastMills = 0;

    private Handler mHandler = new TickingHandler(this);

    /**
     * 振荡回调
     */
    private OnTickListener mOnTickListener;

    public ClockOscillator(Context context) {
        init();
    }

    public ClockOscillator(Fragment fragment) {
        new ClockOscillator(fragment.getContext());
    }

    private void init() {
        start = System.currentTimeMillis();
    }

    /**
     * 设置一个滴嗒监听。当达成间隔时间，就是触发一次
     *
     * @param listener A callback that notifies when the chronometer has incremented on its own.
     */
    public void setOnTickListener(OnTickListener listener) {
        this.mOnTickListener = listener;
    }

    public Long getStart() {
        return start;
    }

    public void setStart(Long start) {
        this.start = start;
    }

    public Long getEnd() {
        return end;
    }

    public void setEnd(Long end) {
        this.end = end;
    }

    public Long getInterval() {
        return interval;
    }

    public void setInterval(Long interval) {
        this.interval = interval;
    }


    /**
     * 开始
     */
    public void start() {
        //记录时间
        mStarted = true;
        performUpdateRunning();
    }

    /**
     * 停止
     */
    public void stop() {
        reset();
        mStarted = false;
        performUpdateRunning();
    }

    /**
     * 重置
     */
    public void reset() {
        lastMills = 0;
    }

    /**
     * 直接振荡一次（未启动时，会触发启动）
     */
    public void tick() {
        dispatchChronometerTick();
    }

    private void performUpdateRunning() {
        boolean running = mStarted;
        Message message = Message.obtain(mHandler, TICK_WHAT);
        if (message != null) {
            //已有振步事件
            mHandler.removeMessages(TICK_WHAT);
        }
        if (running != mRunning) {
            if (running) {
                mHandler.sendMessage(Message.obtain(mHandler, TICK_WHAT));
            } else {
                mHandler.removeMessages(TICK_WHAT);
            }
            mRunning = running;
        }
    }

    long dispatchChronometerTick() {
        long now = System.currentTimeMillis();
        if (mOnTickListener != null) {
            now = System.currentTimeMillis();
            boolean completed = isCompleted();
            if (completed) {
                now = System.currentTimeMillis();
                mOnTickListener.onComplete(this);
            }
            mOnTickListener.onTick(this);
        }
        Log.d(getClass().getSimpleName(), "" + now);
        return now;
    }

    /**
     * 判定振荡器是不是触达停止
     *
     * @return true 停止了
     */
    private boolean isCompleted() {
        boolean completed = false;
        if (end != null && end > 0) {
            completed = end - start <= 0;
        }
        if (!mStarted) {
            completed = false;
        }
        return completed;
    }
    //返回本次振荡时间

    /**
     * A callback that notifies when the chronometer has incremented on its own.
     */
    public interface OnTickListener {

        /**
         * Notification that the chronometer has changed.
         */
        void onTick(ClockOscillator oscillator);

        /**
         * Notification that the chronometer has done.
         */
        void onComplete(ClockOscillator oscillator);
    }

    /**
     * 计算下一次触 发振频的时点
     *
     * @return 下次一次
     */
    private long nextTick() {

        long delayTime = getInterval();
        long now = System.currentTimeMillis();

        if (lastMills != 0L) {
            //修正时间
            delayTime = delayTime - (now - lastMills);
            lastMills += getInterval();
        } else {
            lastMills = now + getInterval();
        }
        return delayTime > 0 ? delayTime : 0;

        /*long now = System.currentTimeMillis();
        if (start != null && now < start) {
            now = start;
        }

        long next = now + (interval - now % interval);
        if (end != null && end < next) {
            return -1L;
        }
        if (lastMills != 0L) {
            interval = interval - (now - lastMills);
            next = lastMills += 1000;
        } else {
            next = lastMills = now + 1000;
        }
        return next;*/
    }

    //时间滴嗒消息处理
    private static class TickingHandler extends Handler {
        private final WeakReference<ClockOscillator> mService;

        TickingHandler(ClockOscillator service) {
            mService = new WeakReference<>(service);
        }

        @Override
        public void handleMessage(Message msg) {
            //处理的时间
            ClockOscillator service = mService.get();
            if (service != null) {
                service.dispatchChronometerTick();
                long nextUptimeMillis = service.nextTick();
                //TODO 因为代码运行是消时间，这里应增加修正量，使得tick时间正常
                sendMessageDelayed(Message.obtain(this, TICK_WHAT), nextUptimeMillis);
            }
        }
    }
}
